﻿using System;
using System.Collections.Generic;

namespace Bravura.Native.PluginBase
{
	/// <summary>
	/// Mixes two or more ISampleable sources.
	/// </summary>
	public class Mixer : ISampleable
	{
		#region Fields

		private int _count;
		private double[] _mixes;
		private ISampleable[] _sources;
		private double _div = 0.5;

		#endregion

		public Mixer(int count, IEnumerable<double> mixes, IEnumerable<ISampleable> sources)
		{
			if (count < 2)
			{
				throw new ArgumentOutOfRangeException("count", "Parameter 'count' must be 2 or greater.");
			}

			int i = 0;
			_count = count;
			_div = 1.0 / count;

			i = 0;
			_mixes = new double[count];
			foreach (var mix in mixes)
			{
				_mixes[i++] = mix;
			}

			i = 0;
			_sources = new ISampleable[count];
			foreach (var source in sources)
			{
				_sources[i++] = source;
			}
		}

		#region Methods

		/// <summary>
		/// Set one mix value.
		/// </summary>
		public void SetMix(int index, double mix)
		{
			_mixes[index] = mix;
		}

		/// <summary>
		/// Set all mix values as if sources are equidistant and circular.
		/// Input domain : 0.0 &lt;= angle &lt;= 1.0
		/// </summary>
		public void SetCircularMix(double angle)
		{
			// initialize mixes
			for (int i = 0; i < _count; i++)
			{
				_mixes[i] = 0.0;
			}

			// calculate mixes
			double mul = _count * angle;
			int seg0 = (int)(mul);
			if (seg0 == _count) seg0 = 0;
			int seg1 = seg0 + 1;
			if (seg1 == _count) seg1 = 0;
			double mix = mul - seg0;

			// set mixes
			_mixes[seg0] = 1.0 - mix;
			_mixes[seg1] = mix;
		}

		/// <summary>
		/// Set all mix values as if sources are equidistant and linear.
		/// Input domain : 0.0 &lt;= angle &lt;= 1.0
		/// </summary>
		public void SetLinearMix(double angle)
		{
			// initialize mixes
			for (int i = 0; i < _count; i++)
			{
				_mixes[i] = 0.0;
			}

			// calculate mixes
			double mul = (_count - 1) * angle;
			int seg0 = (int)(mul);
			if (seg0 == _count) seg0 = 0;
			int seg1 = seg0 + 1;
			if (seg1 == _count) seg1 = 0;
			double mix = mul - seg0;

			// set mixes
			_mixes[seg0] = 1.0 - mix;
			_mixes[seg1] = mix;
		}

		/// <summary>
		/// Get the next sample.
		/// </summary>
		public double Sample()
		{
			double s = 0.0;
			for (int i=0; i<_count; i++)
			{
				s += _mixes[i] * _sources[i].Sample();
			}
			return s;
		}

		#endregion
	}
}
